home *** CD-ROM | disk | FTP | other *** search
/ Programming Languages Suite / ProgramD2.iso / Borland / Borland C++ V5.02 / OCT_AUTO.PAK / AUTOGEN.CPP next >
Text File  |  1997-05-06  |  52KB  |  1,552 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectComponents
  3. // Copyright (c) 1994, 1996 by Borland International, All Rights Reserved
  4. //
  5. // This program reads type libraries (*.OLB; *.TLB) and emits C++ source files
  6. // A typelib filename on the command line forces non-interactive operation.
  7. // Normally generates .HXX and .CXX files for use by OCF automation controller
  8. // A C++ compatible .HPP file can be generated using the entire type library
  9. // by selecting the dialog box option, or by use of the command line options.
  10. //----------------------------------------------------------------------------
  11. #include <ocf/defs.h>      // TComRef
  12. #include <ocf/oleutil.h>   // TComRef
  13. #include <winsys/exbase.h> // TXBase
  14. #include <classlib/pointer.h>
  15. #if defined(BI_PLAT_WIN16)
  16. # include <olenls.h>       // LANGIDFROMCLSID
  17. #endif
  18. #include <iostream.h>
  19. #include <commdlg.h>       // GetFileTitle
  20. #include "autogen.rh"
  21.  
  22. //----------------------------------------------------------------------------
  23. // ITypeInfo and ITypeLib encapsulations
  24. //
  25.  
  26. class TComRef<ITypeInfo> : public TComRefBase<ITypeInfo> {
  27.   public:
  28.     TComRef();
  29.     TComRef(ITypeInfo* iface);
  30.     TComRef(const TComRef<ITypeInfo>& i);
  31.    ~TComRef();
  32.     ITypeInfo* operator =(ITypeInfo* iface);
  33.     TComRef<ITypeInfo>& operator =(const TComRef<ITypeInfo>& i);
  34.     ITypeInfo* operator->() {return I;}
  35.     operator ITypeInfo* far*();
  36.  
  37.     void GetAttr();
  38.     void GetFuncDesc(unsigned int index);
  39.     void GetVarDesc( unsigned int index);
  40.     void GetDocumentation(MEMBERID memberid = MEMBERID_NIL);
  41.     TYPEATTR far* Attr;
  42.     FUNCDESC far* FuncDesc;
  43.     VARDESC  far* VarDesc;
  44.     BSTR Name;
  45.     BSTR Doc;
  46.  
  47.   private:
  48.     void ClearData();
  49. };
  50.  
  51. inline void TComRef<ITypeInfo>::ClearData()
  52. {
  53.   memset((char*)this  + sizeof(TComRefBase<ITypeInfo>), 0,
  54.         sizeof(*this) - sizeof(TComRefBase<ITypeInfo>) );
  55. }
  56.  
  57. TComRef<ITypeInfo>::TComRef() : TComRefBase<ITypeInfo>()
  58. {
  59.   ClearData();
  60. }
  61.  
  62. TComRef<ITypeInfo>::TComRef(ITypeInfo* i) : TComRefBase<ITypeInfo>(i)
  63. {
  64.   ClearData();
  65. }
  66.  
  67. TComRef<ITypeInfo>::TComRef(const TComRef<ITypeInfo>& i)
  68. :
  69.   TComRefBase<ITypeInfo>(i)
  70. {
  71.   ClearData();
  72. }
  73.  
  74. TComRef<ITypeInfo>::~TComRef()
  75. {
  76.   if (Attr)
  77.     I->ReleaseTypeAttr(Attr);
  78.   if (FuncDesc)
  79.     I->ReleaseFuncDesc(FuncDesc);
  80.   if (VarDesc)
  81.     I->ReleaseVarDesc(VarDesc);
  82.   ::SysFreeString(Name);
  83.   ::SysFreeString(Doc);
  84. }
  85.  
  86. inline ITypeInfo* TComRef<ITypeInfo>::operator =(ITypeInfo* iface)
  87. {
  88.   TComRef<ITypeInfo>::~TComRef();
  89.   ClearData();
  90.   return I = iface;
  91. }
  92.  
  93. inline TComRef<ITypeInfo>&
  94. TComRef<ITypeInfo>::operator =(const TComRef<ITypeInfo>& i)
  95. {
  96.   TComRef<ITypeInfo>::~TComRef();
  97.   ClearData();
  98.   I = i.I;
  99.   return *this;
  100. }
  101.  
  102. inline
  103. TComRef<ITypeInfo>::operator ITypeInfo* far*()
  104. {
  105.   TComRef<ITypeInfo>::~TComRef();
  106.   ClearData();
  107.   return &I;
  108. }
  109.  
  110. void TComRef<ITypeInfo>::GetDocumentation(MEMBERID memberid)
  111. {
  112.   ::SysFreeString(Name);
  113.   ::SysFreeString(Doc);
  114.   OLECALL(I->GetDocumentation(memberid, &Name, &Doc, 0, 0),"TypeInfo::GetDoc");
  115. }
  116.  
  117. void TComRef<ITypeInfo>::GetAttr()
  118. {
  119.   if (Attr) I->ReleaseTypeAttr(Attr);
  120.   OLECALL(I->GetTypeAttr(&Attr),"TypeInfo::GetTypeAttr");
  121. }
  122.  
  123. void TComRef<ITypeInfo>::GetFuncDesc(unsigned int index)
  124. {
  125.   if (FuncDesc) I->ReleaseFuncDesc(FuncDesc);
  126.   OLECALL(I->GetFuncDesc(index, &FuncDesc),"TypeInfo::GetFuncDesc");
  127. }
  128.  
  129. void TComRef<ITypeInfo>::GetVarDesc( unsigned int index)
  130. {
  131.   if (VarDesc)  I->ReleaseVarDesc(VarDesc);
  132.   OLECALL(I->GetVarDesc(index, &VarDesc),"TypeInfo::GetVarDesc");
  133. }
  134.  
  135. class TComRef<ITypeLib> : public TComRefBase<ITypeLib> {
  136.   public:
  137.     TComRef();
  138.     TComRef(ITypeLib* iface);
  139.     TComRef(const TComRef<ITypeLib>& i);
  140.    ~TComRef();
  141.     ITypeLib* operator =(ITypeLib* iface) {if (I) I->Release(); return I=iface;}
  142.     ITypeLib* operator =(const TComRef<ITypeLib>& i){if (I) I->Release(); return I=i.I;}
  143.     ITypeLib* operator->() {return I;}
  144.     void GetAttr();
  145.     void GetDocumentation(int index = -1);
  146.     TLIBATTR far* Attr;
  147.     BSTR Name;
  148.     BSTR Doc;
  149. };
  150.  
  151. TComRef<ITypeLib>::TComRef() : TComRefBase<ITypeLib>(),
  152.                                Name(0), Doc(0), Attr(0){}
  153.  
  154. TComRef<ITypeLib>::TComRef(ITypeLib* i) : TComRefBase<ITypeLib>(i),
  155.                                Name(0), Doc(0), Attr(0){}
  156.  
  157. TComRef<ITypeLib>::TComRef(const TComRef<ITypeLib>& i) : TComRefBase<ITypeLib>(i),
  158.                                Name(0), Doc(0), Attr(0){}
  159.  
  160. TComRef<ITypeLib>::~TComRef()
  161. {
  162.   if (Attr)
  163.     I->ReleaseTLibAttr(Attr);
  164.   ::SysFreeString(Name);
  165.   ::SysFreeString(Doc);
  166. }
  167.  
  168. void TComRef<ITypeLib>::GetDocumentation(int index)
  169. {
  170.   ::SysFreeString(Name);
  171.   ::SysFreeString(Doc);
  172.   OLECALL(I->GetDocumentation(index, &Name, &Doc, 0, 0),"TypeLib::GetDoc");
  173. }
  174.  
  175. void TComRef<ITypeLib>::GetAttr()
  176. {
  177.   if (Attr) I->ReleaseTLibAttr(Attr);
  178.   OLECALL(I->GetLibAttr(&Attr),"TypeLib::GetAttr");
  179. }
  180.  
  181. //----------------------------------------------------------------------------
  182. // Error handling facility using local exception object
  183. //
  184.  
  185. struct TLocalError {   // local exception object for this program
  186.   TLocalError(const char* title, const char* message)
  187.                   : Title(title),    Message(message) {}
  188.   const char* Title;
  189.   const char* Message;
  190. };
  191.  
  192. static void Error(const char* title, const char* message)
  193. {
  194.   throw TLocalError(title,message);
  195. }
  196.  
  197. static inline void ErrorIf(int error, const char* title, int resId)
  198. {
  199.   if (error)
  200.     Error(title, (char*)resId);
  201. }
  202.  
  203. static inline void ErrorIf(int error, int resId, const char* message)
  204. {
  205.   if (error)
  206.     Error((char*)resId, message);
  207. }
  208.  
  209. static inline void ErrorIf(int error, const char* title, const char* message)
  210. {
  211.   if (error)
  212.     Error(title,message);
  213. }
  214.  
  215. //----------------------------------------------------------------------------
  216. // ITypeInfo iterator, emits C++ code
  217. //
  218.  
  219. //
  220. // TypeInfo/TypeLib processing flags
  221. //
  222. const int tfEnum      = 1<<TKIND_ENUM;
  223. const int tfRecord    = 1<<TKIND_RECORD;
  224. const int tfModule    = 1<<TKIND_MODULE;
  225. const int tfInterface = 1<<TKIND_INTERFACE;
  226. const int tfDispatch  = 1<<TKIND_DISPATCH;
  227. const int tfCoClass   = 1<<TKIND_COCLASS;
  228. const int tfAlias     = 1<<TKIND_ALIAS;
  229. const int tfUnion     = 1<<TKIND_UNION;
  230. const int tfAllKinds  =(1<<TKIND_MAX)-1;
  231. const int tfScanOnly  = 1<<15;
  232. const int tfLibHeader = 1<<14;
  233. const int tfDispHeader= 1<<13;
  234. const int tfDispImpl  = 1<<12;
  235. const int tfBoolType  = 1<<11;  // OR into libMode[1] if compiler bool support
  236.  
  237. char* infoKind[] = {
  238.   "ENUM","RECORD","MODULE","INTERFACE","DISPATCH","COCLASS","ALIAS","UNION"
  239. };
  240.  
  241. char* typeFlagText[] = {
  242.   "appobject",     // 1   TYPEFLAG_FAPPOBJECT
  243.   "cancreate",     // 2   TYPEFLAG_FCANCREATE
  244.   "licensed",      // 4   TYPEFLAG_FLICENSED
  245.   "predeclid",     // 8   TYPEFLAG_FPREDECLID
  246.   "hidden",        // 16  TYPEFLAG_FHIDDEN
  247.   "control",       // 32  TYPEFLAG_FCONTROL
  248.   "dual",          // 64  TYPEFLAG_FDUAL
  249.   "nonextensible", // 128 TYPEFLAG_FNONEXTENSIBLE
  250.   "oleautomation", // 256 TYPEFLAG_FOLEAUTOMATION
  251.   "TYPEFLAG256",
  252.   "TYPEFLAG512",
  253. };
  254. const int typeFlagCount = COUNTOF(typeFlagText);
  255.  
  256. char* implFlagText[] = {
  257.   "default",       // 1 IMPLTYPEFLAG_FDEFAULT
  258.   "source",        // 2 IMPLTYPEFLAG_FSOURCE
  259.   "restricted",    // 4 IMPLTYPEFLAG_FRESTRICTED
  260.   "IMPLTYPEFLAG8",
  261.   "IMPLTYPEFLAG16",
  262.   "IMPLTYPEFLAG32",
  263. };
  264. const int implFlagCount = COUNTOF(implFlagText);
  265.  
  266. char* memberFlagText[] = {
  267.   "restricted",   // 1   FUNCFLAG_FRESTRICTED (VARFLAG_FREADONLY->invokeKind)
  268.   "source",       // 2   FUNCFLAG_FSOURCE       VARFLAG_FSOURCE
  269.   "bindable",     // 4   FUNCFLAG_FBINDABLE     VARFLAG_FBINDABLE
  270.   "requestedit",  // 8   FUNCFLAG_FREQUESTEDIT  VARFLAG_FREQUESTEDIT
  271.   "displaybind",  // 16  FUNCFLAG_FDISPLAYBIND  VARFLAG_FDISPLAYBIND
  272.   "defaultbind",  // 32  FUNCFLAG_FDEFAULTBIND  VARFLAG_FDEFAULTBIND
  273.   "hidden",       // 64  FUNCFLAG_FHIDDEN       VARFLAG_FHIDDEN
  274.   "FUNCFLAG128",
  275.   "FUNCFLAG256",
  276. };
  277. const int memberFlagCount = COUNTOF(memberFlagText);
  278.  
  279. char* infoCpp[] =     // add delimiting space after identifier as needed
  280.   {"enum ","struct ","","class _ICLASS ","class ","//","typedef ","union "};
  281.  
  282. char* invokeKind[] = {
  283.   "",              // 0 no INVOKEKIND flags
  284.   "method",        // 1 INVOKE_FUNC
  285.   "propget",       // 2 INVOKE_PROPERTYGET
  286.   "prop r/o",      // 3 VAR_DISPATH + VARFLAG_FREADONLY
  287.   "propset",       // 4 INVOKE_PROPERTYPUT
  288.   "?"       ,      // 5
  289.   "propgetset",    // 6
  290.   "prop r/w",      // 7 VAR_DISPATCH
  291.   "propputref",    // 8 INVOKE_PROPERTYPUTREF
  292.   "?",             // 9
  293.   "?"              // 10
  294. };
  295.  
  296. const char VariantReturnType[] = "TAutoVal";
  297. const char StringByRefType[] = "TBSTR";
  298.  
  299. char* dataType[] = {
  300.   "void",          //  0 void
  301.   "NULL",          //  1 SQL NULL
  302.   "short",         //  2 signed short
  303.   "long",          //  3 signed long
  304.   "float",         //  4 IEEE 4-byte
  305.   "double",        //  5 IEEE 8-byte
  306.   "CY",            //  6 currency
  307.   "DATE",          //  7 datetime as double
  308.   "BSTR",          //  8 char far* global mem with int size before
  309.   "IDispatch*",    //  9 dispatch interface
  310.   "SCODE",         // 10 OLE return status
  311.   "bool",          // 11 boolean
  312.   "TAutoVal&",     // 12 VT_VARIANT: pointer to VARIANT union
  313.   "IUnknown*",     // 13 unspecified COM interface
  314.   "<14>",
  315.   "<15>",
  316.   "signed char",   // 17 unsigned char, byte
  317.   "unsigned char",
  318.   "unsigned short",
  319.   "unsigned long",
  320.   "LARGE_INTEGER",
  321.   "ULARGE_INTEGER",
  322.   "signed int",
  323.   "unsigned int",
  324.   "void",
  325.   "HRESULT",
  326.   "VT_PTR",
  327.   "VT_SAFEARRAY",
  328.   "<array>",
  329.   "<userdef>",
  330.   "char*",
  331.   "wchar*",
  332. };
  333. const int dataTypeCount = sizeof(dataType)/sizeof(char*);
  334.  
  335. char* autoType[] = {
  336.   "void",          //  0 void
  337.   "NULL",          //  1 SQL NULL
  338.   "short",         //  2 signed short
  339.   "long",          //  3 signed long
  340.   "float",         //  4 IEEE 4-byte
  341.   "double",        //  5 IEEE 8-byte
  342.   "TAutoCurrency", //  6 currency
  343.   "TAutoDate",     //  7 datetime as double
  344.   "TAutoString",   //  8 OCF encapsulation of string
  345. };
  346. const int autoTypeCount = COUNTOF(autoType);
  347.  
  348. char foldName[256+1] = {
  349.   "_\0_\0_\0f\0_\0_\0_\0_\0_\0_\0S\0_\0OE_\0_\0_\0"
  350.   "_\0_\0_\0_\0_\0_\0_\0_\0_\0TMs\0_\0oe_\0_\0Y\0"
  351.   "_\0_\0c\0L\0_\0Y\0_\0_\0_\0c\0a\0_\0_\0_\0r\0_\0"
  352.   "0\0_\0\062\0\063\0_\0u\0_\0_\0_\0\061\0o\0_\0_\0_\0_\0_\0"
  353.   "A\0A\0A\0A\0AEA\0AEC\0E\0E\0E\0E\0I\0I\0I\0I\0"
  354.   "D\0N\0O\0O\0O\0O\0OEx\0O\0U\0U\0U\0UEY\0_\0ss"
  355.   "a\0a\0a\0a\0aea\0aec\0e\0e\0e\0e\0i\0i\0i\0i\0"
  356.   "o\0n\0o\0o\0o\0o\0oe_\0o\0u\0u\0u\0uey\0_\0y\0"
  357. };
  358.  
  359. const int fnObjectByRef = 1;  // generate code passing proxy object by ref
  360. const int fnPrefixGet   = 2;  // prefix identifier name with "Get"
  361. const int fnPrefixSet   = 4;  // prefix identifier name with "Set"
  362. const int fnClassName   = 8;  // add classname:: before identifier
  363. const int fnAutoTypes   = 16; // translate types to wrappered TAuto...
  364. const int fnIterator    = 32; // emit TAutoIterator<type>&
  365. const int fnReturnType  = 64; // the type to be formatted is the return type
  366.  
  367. //
  368. //
  369. //
  370. bool IsDispObject(ITypeInfo* typeInfo, TYPEDESC far& typeDesc)
  371. {
  372.   if (typeDesc.vt != VT_USERDEFINED)
  373.     return false;
  374.   TComRef<ITypeInfo> refTypeInfo;
  375.   OLECALL(typeInfo->GetRefTypeInfo(typeDesc.hreftype,refTypeInfo),"TypeInfo::GetRefTypeInfo");
  376.   refTypeInfo.GetAttr();
  377.   return refTypeInfo.Attr->typekind==TKIND_DISPATCH;
  378. }
  379.  
  380. TAPointer<char> ClassName;
  381.  
  382. //
  383. //
  384. //
  385. bool FormatTypeName(ITypeInfo* typeInfo, TYPEDESC& typeDescRef,
  386.                     char* name, ostream& out, int flags = 0)
  387. {
  388.   bool isDispObject = false;
  389.   TYPEDESC*  typeDesc = &typeDescRef;
  390.   ARRAYDESC* arrayDesc= 0;
  391.   if (flags & fnIterator)
  392.     out << "TAutoEnumerator<";
  393.  
  394.   bool pointerType = false;
  395.   int derefCount = 0;
  396.   for (; typeDesc->vt == VT_PTR; derefCount++) {
  397.     typeDesc = typeDesc->lptdesc;
  398.     pointerType = true;
  399.   }
  400.  
  401.   if (typeDesc->vt == VT_USERDEFINED) {
  402.     TComRef<ITypeInfo> refTypeInfo;
  403.     OLECALL(typeInfo->GetRefTypeInfo(typeDesc->hreftype,refTypeInfo),"TypeInfo::GetRefTypeInfo");
  404.     refTypeInfo.GetDocumentation();
  405.     out << refTypeInfo.Name;
  406.     refTypeInfo.GetAttr();
  407.     if (flags & fnObjectByRef &&
  408.         refTypeInfo.Attr->typekind==TKIND_DISPATCH && !(flags & fnIterator)) {
  409.       out << '&';    // need reference for automation proxy class
  410.     }
  411.     isDispObject = true;  //!CQ should this be within the prev if block?
  412.   }
  413.   else if (typeDesc->vt == VT_CARRAY) {
  414.     arrayDesc = typeDesc->lpadesc;
  415.     FormatTypeName(typeInfo, arrayDesc->tdescElem, 0, out);
  416.   }
  417.   else {
  418. #if 0
  419.     if ((flags & fnAutoTypes) && (typeDesc->vt & 31) < autoTypeCount)
  420.       out << autoType[typeDesc->vt & 31];
  421.     else
  422.       out << dataType[typeDesc->vt & 31];
  423. #else
  424.     int typeIndex = typeDesc->vt & 31;
  425.     if ((flags & fnAutoTypes) && typeIndex < autoTypeCount) {
  426.       if (!pointerType || typeIndex != 8 /*TAutoString*/)
  427.         out << autoType[typeIndex];
  428.       else
  429.         out << StringByRefType;
  430.     }
  431.     else {
  432.       if ((flags & fnReturnType) && typeIndex == 12)
  433.         out << VariantReturnType;
  434.       else
  435.         out << dataType[typeIndex];
  436.     }
  437. #endif
  438.   }
  439.   if (typeDesc->vt & VT_BYREF)  // should never happen
  440.     derefCount++;
  441.  
  442.   while (derefCount--)
  443.     out << "*";
  444.   if (flags & fnIterator)
  445.     out << ">&";
  446.  
  447.   if (name) {
  448.     char* buf;
  449.     int len = lstrlen(name);
  450.     int nonascii = 0;
  451.     for (unsigned char far* pc = (unsigned char far*)name; *pc; pc++)
  452.       if (*pc >= 128)
  453.         nonascii++;
  454.  
  455.     if (nonascii) {
  456.       unsigned char far* pn = (unsigned char far*)name;
  457.       buf = new char[nonascii + len + 1];
  458.       name = buf;
  459.       unsigned char c;
  460.       do {
  461.         c = *pn++;
  462.         if (c < 128) {
  463.           *buf++ = c;
  464.         }
  465.         else {
  466.           char* px = foldName + (c-128)*2;
  467.           *buf++ = *px++;
  468.           if (*px)
  469.             *buf++ = *px;
  470.         }
  471.       } while (c);
  472.     }
  473.  
  474.     out << ' ';
  475.     if ((char*)ClassName && (flags & fnClassName))
  476.       out << (char*)ClassName << "::";
  477.     if (flags & fnPrefixGet)
  478.       out << "Get";
  479.     if (flags & fnPrefixSet)
  480.       out << "Set";
  481.     out << name;
  482.  
  483.     // If name's same as ClassName, it will look like a constructor;
  484.     // So append an underscore.
  485.     //
  486.     if ((char*)ClassName) {
  487.       if(!(flags & fnPrefixGet) &&
  488.          !(flags & fnPrefixSet) && 
  489.          !strcmpi(name, ClassName)) {
  490.         out << '_';
  491.       }
  492.     } 
  493.  
  494.     if (nonascii)
  495.       delete name;
  496.   }
  497.   if (arrayDesc)
  498.     for (int dim = 0; dim < arrayDesc->cDims; dim++)
  499.       out << '[' << arrayDesc->rgbounds[dim].cElements << ']';
  500.   return isDispObject;
  501. }
  502.  
  503. //
  504. //
  505. //
  506. void FormatGuidLang(GUID far& guid, LCID locale, ostream& out)
  507. {
  508.   char guidBuf[38+1] = "{NULL}";
  509.   int notNull = 0;
  510.   int far* pg = (int far*)&guid;
  511.  
  512.   for (int i = sizeof(GUID)/sizeof(int); i--; pg++)
  513.     notNull |= *pg;
  514.  
  515.   if (notNull)
  516.     wsprintf(guidBuf, "{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}",
  517.              guid.Data1, guid.Data2, guid.Data3,
  518.              guid.Data4[0], guid.Data4[1], guid.Data4[2], guid.Data4[3],
  519.              guid.Data4[4], guid.Data4[5], guid.Data4[6], guid.Data4[7]);
  520.   out << ' ' << guidBuf << '\\' << hex << LANGIDFROMLCID(locale) << dec;
  521. }
  522.  
  523. //
  524. //
  525. //
  526. void FormatVers(int major, int minor, ostream& out)
  527. {
  528.   if (major)
  529.     out << ' ' << major << '.' << minor;
  530. }
  531.  
  532. //
  533. //
  534. //
  535. void FormatDispId(DISPID id, int invKind, uint16 flags, ostream& out)
  536. {
  537.   out << "[id(";
  538.   if ((long)id > 9999 || (long)id < -9999)
  539.     out << "0x" << hex << id << dec;
  540.   else
  541.     out << id;
  542.   out << ')';
  543.   if (invKind)
  544.     out << ", " << invokeKind[invKind];
  545.  
  546.   for (int i = 0; flags; i++, flags >>= 1) {
  547.     if (flags & 1)
  548.       out << ", " << memberFlagText[i];
  549.   }
  550.   out << ']';
  551. }
  552.  
  553. //
  554. // assumed that caller of this function called GetDocumenation() on typeInfo
  555. //
  556. void FormatTypeInfo(TComRef<ITypeInfo>& typeInfo, int mode, ostream& out)
  557. {
  558. //typeInfo.GetDocumentation();
  559.   typeInfo.GetAttr();
  560.   int kind = typeInfo.Attr->typekind;
  561.  
  562.   if (typeInfo.Attr->typekind != TKIND_ALIAS) {
  563.     out << "\n// TKIND_" << infoKind[kind] << ": " << typeInfo.Name;
  564.     FormatVers(typeInfo.Attr->wMajorVerNum,typeInfo.Attr->wMinorVerNum,out);
  565.     FormatGuidLang(typeInfo.Attr->guid, typeInfo.Attr->lcid, out);
  566.     out << ' ' << typeInfo.Doc << '\n';
  567.  
  568.     int typeFlags = typeInfo.Attr->wTypeFlags;
  569.     if (typeFlags && !(mode & (tfDispHeader | tfDispImpl))) {
  570.       char* delim = "//  [";
  571.       for (int tflag = 0; tflag < implFlagCount; tflag++, typeFlags >>= 1)
  572.         if (typeFlags & 1) {
  573.           out << delim << typeFlagText[tflag];
  574.           delim = ", ";
  575.       }
  576.       out << "]\n";
  577.     }
  578.     out << '\n';
  579.     if (!(mode & tfDispImpl))
  580.       out << infoCpp[kind];
  581.   }
  582.  
  583.   switch (kind) {
  584.     case TKIND_MODULE: {
  585.       for (int varIndex = 0; varIndex < typeInfo.Attr->cVars; varIndex++) {
  586.         typeInfo.GetVarDesc(varIndex);
  587.         typeInfo.GetDocumentation(typeInfo.VarDesc->memid);
  588.         out << "    ";
  589.         FormatTypeName(typeInfo, typeInfo.VarDesc->elemdescVar.tdesc, typeInfo.Name, out);
  590.         out << "; // ";
  591.         int invKind = typeInfo.VarDesc->wVarFlags & VARFLAG_FREADONLY ? 3 : 7;
  592.         FormatDispId(typeInfo.VarDesc->memid, invKind,
  593.                      typeInfo.VarDesc->wVarFlags & ~VARFLAG_FREADONLY, out);
  594.         out << '\n';
  595.       }
  596.       for (int funcIndex = 0; funcIndex < typeInfo.Attr->cFuncs; funcIndex++) {
  597.         typeInfo.GetFuncDesc(funcIndex);
  598.         typeInfo.GetDocumentation(typeInfo.FuncDesc->memid);
  599.         int argCount = typeInfo.FuncDesc->cParams;
  600.         int argIndex;
  601.         TBSTR argName[35];      // max. arg count + 1, minimum 35 for MSWord6
  602.         unsigned int nameCount;
  603.         OLECALL(typeInfo->GetNames(typeInfo.FuncDesc->memid, argName[0],
  604.                                    COUNTOF(argName), &nameCount), "TKIND_INTERFACE GetNames");
  605.         if (typeInfo.Doc)
  606.           out << "    // " << typeInfo.Doc << '\n';
  607.         out << "    ";
  608.         for (argIndex = 0; argIndex <= argCount; argIndex++) {
  609.           ELEMDESC far* elemDesc = argIndex==0 ?
  610.                           &typeInfo.FuncDesc->elemdescFunc :
  611.                           typeInfo.FuncDesc->lprgelemdescParam + (argIndex-1);
  612.           FormatTypeName(typeInfo, elemDesc->tdesc, argIndex < nameCount ?
  613.                          (char far*)argName[argIndex] : (char far*)0, out);
  614.           if (argIndex == 0)
  615.             out << '(';
  616.           else if (argIndex != argCount)
  617.             out << ", ";
  618.         }
  619.         out << "); // ";
  620.         FormatDispId(typeInfo.FuncDesc->memid, 0,
  621.                      typeInfo.FuncDesc->wFuncFlags, out);
  622.         out << '\n';
  623.       }
  624.       out << "\n";
  625.       break;
  626.     }
  627.  
  628.     case TKIND_UNION:
  629.     case TKIND_RECORD: {
  630.       out << typeInfo.Name << " {\n"; /*}*/
  631.       for (int membIndex = 0; membIndex < typeInfo.Attr->cVars; membIndex++) {
  632.         typeInfo.GetVarDesc(membIndex);
  633.         typeInfo.GetDocumentation(typeInfo.VarDesc->memid);
  634.         out << "  ";
  635.         FormatTypeName(typeInfo, typeInfo.VarDesc->elemdescVar.tdesc, typeInfo.Name, out);
  636.         out << ";\n";
  637.       }
  638.       /*{*/ out << "};\n";
  639.       break;
  640.     }
  641.     case TKIND_ALIAS: {
  642.       out << infoCpp[kind] << ' ';
  643.       FormatTypeName(typeInfo, typeInfo.Attr->tdescAlias, typeInfo.Name, out);
  644.       out << ";\n";
  645.       break;
  646.     }
  647.     case TKIND_ENUM: {
  648.       out << typeInfo.Name << " {\n"; /*}*/
  649.       for (int enumIndex = 0; enumIndex < typeInfo.Attr->cVars; enumIndex++) {
  650.         typeInfo.GetVarDesc(enumIndex);
  651.         typeInfo.GetDocumentation(typeInfo.VarDesc->memid);
  652.         out << "  " << typeInfo.Name;
  653.         if (typeInfo.VarDesc->varkind == VAR_CONST
  654.          && typeInfo.VarDesc->lpvarValue->vt == VT_I2)
  655.           out << " = " << typeInfo.VarDesc->lpvarValue->iVal;
  656.         out << ",\n";
  657.       }
  658.       /*{*/ out << "};\n";
  659.       break;
  660.     }
  661.     case TKIND_INTERFACE: {
  662.       out << typeInfo.Name;
  663.       int baseCount = typeInfo.Attr->cImplTypes;
  664.       for (int baseIndex = 0; baseIndex < baseCount; baseIndex++) {
  665.         out << (baseIndex ==0 ? " : public " : ", public ");
  666.         HREFTYPE hrefType;
  667.         OLECALL(typeInfo->GetRefTypeOfImplType(baseIndex, &hrefType),"TKIND_INTERFACE GetRefTypeofImplType");
  668.         TComRef<ITypeInfo> refTypeInfo;
  669.         OLECALL(typeInfo->GetRefTypeInfo(hrefType, refTypeInfo),"TKIND_INTERFACE GetRefTypeInfo");
  670.         refTypeInfo.GetDocumentation();
  671.         out << refTypeInfo.Name;
  672.       }
  673.       out << " {\n  public:\n"; /*}*/
  674.       for (int funcIndex = 0; funcIndex < typeInfo.Attr->cFuncs; funcIndex++) {
  675.         typeInfo.GetFuncDesc(funcIndex);
  676.         typeInfo.GetDocumentation(typeInfo.FuncDesc->memid);
  677.         int argCount = typeInfo.FuncDesc->cParams;
  678.         int argIndex;
  679.         TBSTR argName[35];      // max. arg count + 1, minimum 35 for MSWord6
  680.         unsigned int nameCount;
  681.         OLECALL(typeInfo->GetNames(typeInfo.FuncDesc->memid, argName[0],
  682.                                    sizeof(argName)/sizeof(TBSTR), &nameCount),"TKIND_INTERFACE GetNames");
  683.         if (typeInfo.Doc)
  684.           out << "    // " << typeInfo.Doc << '\n';
  685.         if (typeInfo.FuncDesc->wFuncFlags & FUNCFLAG_FRESTRICTED)
  686.           out << "//  ";    // not accessible from dispatch controller
  687.         else
  688.           out << "    ";
  689.         for (argIndex = 0; argIndex <= argCount; argIndex++) {
  690.           ELEMDESC far* elemDesc = argIndex==0 ?
  691.                           &typeInfo.FuncDesc->elemdescFunc :
  692.                           typeInfo.FuncDesc->lprgelemdescParam + (argIndex-1);
  693.           FormatTypeName(typeInfo, elemDesc->tdesc, argIndex < nameCount ?
  694.                          (char far*)argName[argIndex] : (char far*)0, out);
  695.           if (argIndex == 0)
  696.             out << '(';
  697.           else if (argIndex != argCount)
  698.             out << ", ";
  699.         }
  700.         out << ") = 0; // ";
  701.         FormatDispId(typeInfo.FuncDesc->memid, 0,
  702.                      typeInfo.FuncDesc->wFuncFlags, out);
  703.         out << '\n';
  704.       }
  705.       /*{*/ out << "};\n";
  706.       break;
  707.     }
  708.     case TKIND_DISPATCH: {
  709.       TYPEDESC typeDescVoid;
  710.       typeDescVoid.vt = VT_VOID;
  711.       char semi;
  712.  
  713.       ClassName = new char[lstrlen(typeInfo.Name)+1];
  714.       lstrcpy(ClassName, typeInfo.Name);
  715.       if (mode & tfDispImpl) {
  716.         semi = ' ';
  717.       }
  718.       else {
  719.         semi = ';';
  720.         out << typeInfo.Name;
  721.         if (mode & tfDispHeader)
  722.           out << " : public TAutoProxy";
  723.         out << " {\n  public:\n"; /*}*/
  724.         if (mode & tfDispHeader)
  725.           out << "    " << typeInfo.Name << "() : TAutoProxy(0x"
  726.               << hex << LANGIDFROMLCID(typeInfo.Attr->lcid) << dec << ") {}\n";
  727.       }
  728.       for (int varIndex = 0; varIndex < typeInfo.Attr->cVars; varIndex++) {
  729.         int formatFlags = 0;
  730.         if (mode & tfDispHeader)
  731.           formatFlags = fnObjectByRef | fnPrefixGet | fnAutoTypes;
  732.         if (mode & tfDispImpl)
  733.           formatFlags = fnObjectByRef | fnPrefixGet | fnClassName | fnAutoTypes;
  734.         typeInfo.GetVarDesc(varIndex);
  735.         TYPEDESC& typeDesc = typeInfo.VarDesc->elemdescVar.tdesc;
  736.         int invKind = typeInfo.VarDesc->wVarFlags & VARFLAG_FREADONLY ? 3 : 7;
  737.         // should we insure that (type.Info.VarDesc->varkind==VAR_DISPATCH) ?
  738.         typeInfo.GetDocumentation(typeInfo.VarDesc->memid);
  739.         if (!(mode & tfDispImpl) && typeInfo.Doc)
  740.           out << "    // " << typeInfo.Doc << '\n';
  741.         bool isDispObject = IsDispObject(typeInfo, typeDesc);
  742.         bool boolProp = !(mode & tfBoolType) && typeDesc.vt == VT_BOOL;
  743.         bool boolRef  = !(mode & tfBoolType) && typeDesc.vt == VT_PTR
  744.                                     && typeDesc.lptdesc->vt == VT_BOOL;
  745.         do {
  746.           char* argName = 0;
  747.           if (!(mode & tfDispImpl))
  748.             out << "    ";
  749.           if (formatFlags == 0 ||
  750.              !((formatFlags & fnPrefixSet) || isDispObject)){
  751.             if (formatFlags & fnPrefixGet)
  752.               formatFlags |= fnReturnType;
  753.             else
  754.               formatFlags &= ~fnReturnType;
  755.             FormatTypeName(typeInfo, typeDesc, typeInfo.Name, out, formatFlags);
  756.             if (formatFlags & fnPrefixGet)
  757.               out << "()";
  758.             out << semi << "    ";
  759.           }
  760.           else {
  761.             FormatTypeName(typeInfo,typeDescVoid,typeInfo.Name,out,formatFlags);
  762.             if (mode & tfDispImpl)
  763.               argName = isDispObject ? "obj" : "val";
  764.             out << '(';
  765.             FormatTypeName(typeInfo,typeDesc,argName,out,
  766.                            formatFlags & (fnObjectByRef | fnAutoTypes));
  767.             out << ')' << semi;
  768.           }
  769.           if (mode & tfDispImpl) {
  770.             out << "\n{\n  AUTONAMES0(\"" << typeInfo.Name
  771.                 << "\")\n  AUTOARGS0()\n  AUTOCALL_PROP_"; /*}*/
  772.             if (formatFlags & fnPrefixSet)
  773.               out << "SET";
  774.             else if (isDispObject)
  775.               out << "REF";
  776.             else if (boolProp)
  777.               out << "CONV(TBool)";
  778.             else if (boolRef)
  779.               out << "CONV(TBool&)";
  780.             else
  781.               out << "GET";
  782.             if (argName) {
  783.               if (boolProp)
  784.                 out << "(TBool(" << argName << "))";
  785.               else if (boolRef)
  786.                 out << "(TBool&(" << argName << "))";
  787.               else
  788.                 out << '(' << argName << ')';
  789.             }
  790.             /*{*/ out << "\n}\n";
  791.           }
  792.           else {
  793.             out << " // ";
  794.             FormatDispId(typeInfo.VarDesc->memid, invKind,
  795.                          typeInfo.VarDesc->wVarFlags & ~VARFLAG_FREADONLY, out);
  796.           }
  797.           out << '\n';
  798.           if ((formatFlags & fnPrefixGet) && invKind == 7)
  799.             formatFlags ^= (fnPrefixGet | fnPrefixSet);
  800.           else
  801.             formatFlags = 0;
  802.         } while (formatFlags & fnPrefixSet);
  803.       }
  804.       for (int funcIndex = 0; funcIndex < typeInfo.Attr->cFuncs; funcIndex++) {
  805.         int formatFlags = 0;
  806.         if (mode & tfDispHeader)
  807.           formatFlags = fnObjectByRef | fnAutoTypes;
  808.         if (mode & tfDispImpl)
  809.           formatFlags = fnObjectByRef | fnAutoTypes | fnClassName;
  810.         typeInfo.GetFuncDesc(funcIndex);
  811.         if (typeInfo.FuncDesc->wFuncFlags & FUNCFLAG_FRESTRICTED)
  812.           continue;                 // not accessible from dispatch controller
  813.         typeInfo.GetDocumentation(typeInfo.FuncDesc->memid);
  814.         int argCount = typeInfo.FuncDesc->cParams;
  815.         TBSTR argNames[35];     // max. arg count + 1, minimum 35 for MSWord6
  816.         unsigned int nameCount;
  817.         OLECALL(typeInfo->GetNames(typeInfo.FuncDesc->memid, argNames[0],
  818.                 sizeof(argNames)/sizeof(TBSTR), &nameCount),"TKIND_DISPATCH GetNames");
  819.         if (!(mode & tfDispImpl)) {
  820.           if (typeInfo.Doc)
  821.             out << "    // " << typeInfo.Doc << '\n';
  822.           out << "    ";
  823.         }
  824.         int argIndex  = -1;   // index into ELEMDESC[], -1 for return type
  825.         int nameIndex = 0;    // index into name table, no propset param name
  826.         int outParam  = 0;    // index of type/name being output
  827.         bool voidRet = false;
  828.         bool boolRet = false;
  829.         bool boolRetRef = false;
  830.         bool isObject = false;
  831.         bool isIterator = (typeInfo.FuncDesc->memid == DISPID_NEWENUM);
  832.         for ( ; argIndex<argCount; argIndex++, outParam++) {
  833.           TYPEDESC far* typeDesc = &typeInfo.FuncDesc->elemdescFunc.tdesc;
  834.           if (argIndex >= 0)  {        // processing an argument
  835.             typeDesc = &typeInfo.FuncDesc->lprgelemdescParam[argIndex].tdesc;
  836.           }
  837.           else if (outParam == 0 && (mode & (tfDispHeader | tfDispImpl)) &&
  838.                      (IsDispObject(typeInfo, *typeDesc) || isIterator)) {
  839.             typeDesc = &typeDescVoid;
  840.             argIndex--;           // reprocess return as first arg
  841.             isObject = true;
  842.           }
  843.           else if (typeDesc->vt == VT_VOID || typeDesc->vt == VT_EMPTY) {
  844.             voidRet = true;
  845.           }
  846.           else if (!(mode & tfBoolType) && typeDesc->vt == VT_BOOL) {
  847.             boolRet = true;
  848.           }
  849.           else if (!(mode & tfBoolType) && typeDesc->vt == VT_PTR
  850.                                  && typeDesc->lptdesc->vt == VT_BOOL) {
  851.             boolRetRef = true;
  852.           }
  853.           char far* name = 0;
  854.           char argName[10];
  855.           if (isObject && argIndex == -1) {
  856.             if (mode & tfDispImpl)
  857.               name = "obj";
  858.             if (isIterator)
  859.               formatFlags |= fnIterator;
  860.           }
  861.           else if (argIndex==0 && typeInfo.FuncDesc->invkind>=INVOKE_PROPERTYPUT) {
  862.             if (mode & tfDispImpl)
  863.               name = "val";
  864.           }
  865.           else if (nameIndex >= nameCount) {
  866.             if (mode & tfDispImpl)
  867.               wsprintf(name = argName, "arg%d", argIndex+1);
  868.           }
  869.           else
  870.             name = argNames[nameIndex++];
  871.  
  872.           if (outParam == 0 && (mode & (tfDispHeader | tfDispImpl))) {
  873.             if (typeInfo.FuncDesc->invkind>=INVOKE_PROPERTYPUT)
  874.               formatFlags |= fnPrefixSet;  // must differentiate from get
  875.             else if (typeInfo.FuncDesc->invkind==INVOKE_PROPERTYGET) {
  876.               if (isIterator)
  877.                 name = "Enumerate";
  878.               else
  879.                 formatFlags |= fnPrefixGet;  // get&set may have same name
  880.             }
  881.           }
  882.           if (argIndex == -1)
  883.             formatFlags |=  fnReturnType;
  884.           else
  885.             formatFlags &= ~fnReturnType;
  886.           FormatTypeName(typeInfo, *typeDesc, name, out, formatFlags);
  887.           formatFlags &= ~fnIterator;
  888.           if (outParam == 0) {
  889.             out << '(';
  890.             formatFlags &= ~(fnClassName | fnPrefixGet | fnPrefixSet);
  891.           }
  892.           else if (argIndex != argCount-1)
  893.             out << ", ";
  894.         }
  895.         out << ')' << semi;
  896.         if (mode & tfDispImpl) {
  897.           out << "\n{\n  AUTONAMES0("; /*}*/
  898.           if (isIterator)
  899.             out << "DISPID_NEWENUM";
  900.           else
  901.             out << '"' << typeInfo.Name << '"';
  902.           if (typeInfo.FuncDesc->invkind>=INVOKE_PROPERTYPUT)
  903.             argCount--;
  904.           out << ")\n  AUTOARGS" << argCount << '(';
  905.           argIndex = 1;                 // 1-based for following loop
  906.           for ( ; argIndex <= argCount; argIndex++) { // 1-based
  907.             if (argIndex != 1)
  908.               out << ", ";
  909.             TYPEDESC far& typeDesc =
  910.                        typeInfo.FuncDesc->lprgelemdescParam[argIndex-1].tdesc;
  911.             bool boolArg = !(mode & tfBoolType) && typeDesc.vt == VT_BOOL;
  912.             bool boolRef = !(mode & tfBoolType) && typeDesc.vt == VT_PTR
  913.                                        && typeDesc.lptdesc->vt == VT_BOOL;
  914.             if (boolArg)
  915.               out << "TBool(";
  916.             else if (boolRef)
  917.               out << "TBool&(";
  918.             if (argIndex < nameCount)
  919.               out << argNames[argIndex];
  920.             else
  921.               out << "arg" << argIndex;
  922.             if (boolArg || boolRef)
  923.               out << ")";
  924.           }
  925.           out << ")\n  AUTOCALL_";
  926.           if (typeInfo.FuncDesc->invkind==INVOKE_PROPERTYGET) {
  927.             if (isObject)
  928.               out << "PROP_REF(obj)";
  929.             else
  930.               out << "PROP_GET";
  931.           }
  932.           else if (typeInfo.FuncDesc->invkind==INVOKE_PROPERTYPUT) {
  933.             out << "PROP_SET(val)";
  934.           }
  935.           else {
  936.             out << "METHOD_";
  937.             if (isObject)
  938.               out << "REF(obj)";
  939.             else if (voidRet)
  940.               out << "VOID";
  941.             else if (boolRet)
  942.               out << "CONV(TBool)";
  943.             else if (boolRetRef)
  944.               out << "CONV(TBool&)";
  945.             else
  946.               out << "RET";
  947.           }
  948.           /*{*/ out << "\n}\n";  //(for editor brace check)
  949.         }
  950.         else {
  951.           out << " // ";
  952.           FormatDispId(typeInfo.FuncDesc->memid,
  953.                        typeInfo.FuncDesc->invkind,
  954.                        typeInfo.FuncDesc->wFuncFlags, out);
  955.         }
  956.         out << '\n';
  957.       }
  958.       if (!(mode & tfDispImpl))
  959.         /*{*/ out << "};\n";
  960.       break;
  961.     }
  962.     case TKIND_COCLASS: {
  963.       for (unsigned int cindex=0; cindex<typeInfo.Attr->cImplTypes; cindex++) {
  964.         HREFTYPE hrefType;
  965.         OLECALL(typeInfo->GetRefTypeOfImplType(cindex, &hrefType), "GetRefTypeofImplType");
  966.         int typeFlags;
  967.         OLECALL(typeInfo->GetImplTypeFlags(cindex, &typeFlags), "GetImplTypeFlags");
  968.         TComRef<ITypeInfo> refTypeInfo;
  969.         OLECALL(typeInfo->GetRefTypeInfo(hrefType, refTypeInfo),"TKIND_COCLASS GetRefTypeInfo");
  970.         refTypeInfo.GetDocumentation();
  971.         out << "\n//  " << refTypeInfo.Name;
  972.         char* delim = "  [";
  973.         if (typeFlags) {
  974.           for (int iflag = 0; iflag < implFlagCount; iflag++, typeFlags >>= 1)
  975.             if (typeFlags & 1) {
  976.               out << delim << implFlagText[iflag];
  977.               delim = ", ";
  978.             }
  979.           out << ']';
  980.         }
  981.       }
  982.       out << "\n\n";
  983.       break;
  984.     }
  985.   }
  986.   ClassName = 0;
  987. }
  988.  
  989. //----------------------------------------------------------------------------
  990. // Local class to hold selection and iterator information for type library
  991. //
  992.  
  993. class TLogTypeInfo {
  994.   public:
  995.     typedef bool (*TCall)(TLogTypeInfo&);
  996.  
  997.     TLogTypeInfo(HWND hWnd);
  998.    ~TLogTypeInfo()        {delete SelectList;}
  999.     bool  Report();
  1000.     HWND  GetWindow()      {return Window;}
  1001.     int   GetSelectCount() {return SelectCount;}
  1002.     int*  GetSelectList()  {return SelectList;}
  1003.     void  SetSelectList(int count, int* list);
  1004.     int   GetRequestCount() {return ReqCount;}
  1005.     void  SetRequestList(int count, int* list, char** names);
  1006.     void  SetCallback(TLogTypeInfo::TCall proc) {Proc = proc;}
  1007.     bool  MatchRequest();  // return true to continue, false if all done
  1008.     char* ExtractRequest();// return unmatched type name, 0 if list empty
  1009.     void ClearLists();
  1010.     int   Index;        // returned selection index, within user select types
  1011.     int   TypeIndex;    // returned typeinfo index, within entire type library
  1012.     char* TypeKind;     // returned typeinfo kind text
  1013.     char far* TypeName; // returned typeinfo name text
  1014.   private:
  1015.     char** ReqNames;    // temp requested type names
  1016.     int    ReqCount;    // temp requested name count
  1017.     int*   SelectList;  // list of selected typeinfos in type library
  1018.     int    SelectCount; // number of selected items
  1019.     HWND   Window;      // window to receive data
  1020.     TCall  Proc;        // callback function to display data
  1021. };
  1022.  
  1023. inline TLogTypeInfo::TLogTypeInfo(HWND hWnd)
  1024.                     : Window(hWnd), SelectList(0), Proc(0)
  1025. {
  1026.   ClearLists();  // SelectList must be 0 to prevent delete of garbage
  1027. }
  1028.  
  1029. inline void TLogTypeInfo::ClearLists()
  1030. {
  1031.   if (!ReqNames)
  1032.     delete SelectList;
  1033.   ReqNames = 0;
  1034.   SelectList = 0;
  1035.   SelectCount = 0;
  1036.   ReqCount = 0;
  1037. }
  1038.  
  1039. inline void TLogTypeInfo::SetSelectList(int count, int* list)
  1040. {
  1041.   ClearLists();
  1042.   SelectCount = count;
  1043.   SelectList = list;
  1044. }
  1045.  
  1046. inline void TLogTypeInfo::SetRequestList(int count, int* list, char** names)
  1047. {
  1048.   ClearLists();
  1049.   ReqCount = count;
  1050.   ReqNames = names;
  1051.   SelectList = list;
  1052. }
  1053.  
  1054. inline bool TLogTypeInfo::Report()
  1055. {
  1056.   return Proc ? Proc(*this) : MatchRequest();
  1057. }
  1058.  
  1059. bool TLogTypeInfo::MatchRequest()
  1060. {
  1061.   if (!ReqCount)
  1062.     return false;
  1063.   for (int i = 0; i < ReqCount; i++) {
  1064.     if (stricmp(TypeName, ReqNames[i]) == 0) {
  1065.       SelectList[SelectCount++] = TypeIndex;
  1066.       if (--ReqCount != i)
  1067.         memcpy(&ReqNames[i],&ReqNames[i+1],(ReqCount-i)*sizeof(int));
  1068.       return ReqCount != 0;
  1069.     }
  1070.   }
  1071.   return true;  // keep going
  1072. }
  1073.  
  1074. char* TLogTypeInfo::ExtractRequest()
  1075. {
  1076.   if (!ReqCount)
  1077.     return 0;
  1078.   char* name = ReqNames[0];
  1079.   if (--ReqCount)
  1080.     memcpy(&ReqNames[0], &ReqNames[1], ReqCount*sizeof(int));
  1081.   return name;
  1082. }
  1083.  
  1084. //----------------------------------------------------------------------------
  1085. // ITypeLib iterator, emits file header info, calls ITypeInfo iterator
  1086. //
  1087.  
  1088. void ReadTypeLib(char* libName, char* incName, int mode, ostream& out,
  1089.                  TLogTypeInfo& log)
  1090. {
  1091.   try {       // catch OLE errors, no OLE calls are made outside of this block
  1092.     char nameBuf[50];      // large enough for basename.tlb, overflow not fatal
  1093.     TOleAllocator oleMem(0);
  1094.     TComRef<ITypeLib> typeLib;
  1095.     TComRef<ITypeInfo> coclassInfo;
  1096.     OLECALL(::LoadTypeLib(libName, typeLib),"LoadTypeLib");
  1097.     typeLib.GetAttr();
  1098.     if (mode & tfLibHeader) {
  1099.       typeLib.GetDocumentation();
  1100.       if (::GetFileTitle(libName, nameBuf, sizeof(nameBuf)) <= 0)
  1101.         out << "// Type Library: " << nameBuf;
  1102.       out << "  " << typeLib.Doc << '\n';
  1103.       out << "// " << typeLib.Name;
  1104.       FormatVers(typeLib.Attr->wMajorVerNum, typeLib.Attr->wMinorVerNum, out);
  1105.       FormatGuidLang(typeLib.Attr->guid, typeLib.Attr->lcid, out);
  1106.       out << "\n\n";
  1107.     }
  1108.     int infoCount = typeLib->GetTypeInfoCount();
  1109.     if (incName)
  1110.       out << "#include " << incName << "\n";
  1111.     if (mode & tfDispHeader) {
  1112.       for (int infoIndex = 0; infoIndex < infoCount; infoIndex++) {
  1113.         TYPEKIND infoType;
  1114.         typeLib->GetTypeInfoType(infoIndex, &infoType);
  1115.         if (infoType == TKIND_DISPATCH) {
  1116.           TComRef<ITypeInfo> typeInfo;
  1117.           OLECALL(typeLib->GetTypeInfo(infoIndex, typeInfo),"typeLib->GetTypeInfo");
  1118.           typeInfo.GetDocumentation();
  1119.           out << "\nclass " << typeInfo.Name << ';';
  1120.         }
  1121.         if (infoType == TKIND_COCLASS) {
  1122.           OLECALL(typeLib->GetTypeInfo(infoIndex, coclassInfo),"typeLib->GetTypeInfo");
  1123.         }
  1124.       }
  1125.       out << "\n";
  1126.     }
  1127.     // need to scan coclass typeinfo for [source] classes
  1128.     // and eliminate them from HXX/CXX code generation
  1129.     // eventually should emit server code tables
  1130.     //
  1131.     int  infoIndex = 0;
  1132.     int  selIndex  = 0;
  1133.     int  selCount  = log.GetSelectCount();
  1134.     int* selList   = log.GetSelectList();
  1135.     for (; infoIndex < infoCount; infoIndex++) {
  1136.       if (selList && !(mode & tfScanOnly)) {     // partial selection
  1137.         if (!selCount || infoIndex != selList[selIndex])
  1138.           continue;
  1139.         selCount--;
  1140.       }
  1141.       TYPEKIND infoType;
  1142.       typeLib->GetTypeInfoType(infoIndex, &infoType);
  1143.       if (((1<<infoType) & mode) == 0)
  1144.         continue;
  1145.       TComRef<ITypeInfo> typeInfo;
  1146.       OLECALL(typeLib->GetTypeInfo(infoIndex, typeInfo),"GetTypeInfo");
  1147.       typeInfo.GetDocumentation();
  1148.       typeInfo.GetAttr();
  1149.       log.TypeIndex = infoIndex;
  1150.       log.Index     = selIndex++;
  1151.       log.TypeName  = typeInfo.Name;
  1152.       log.TypeKind  = infoKind[infoType];
  1153.       if (!log.Report())
  1154.         break;
  1155.       if (mode & tfScanOnly)
  1156.         continue;
  1157.       FormatTypeInfo(typeInfo, mode, out);
  1158.     }
  1159.   }
  1160.   catch(TXOle& x) {  // convert OLE exception into local exception
  1161.     Error(libName, x.why().c_str());
  1162.   }
  1163. }
  1164.  
  1165. //----------------------------------------------------------------------------
  1166. // Command line and UI processing, creates streams
  1167. //
  1168.  
  1169. #include <stdio.h>
  1170. #include <conio.h>
  1171. #include <string.h>
  1172. #include <fstream.h>
  1173. #include <strstrea.h>
  1174.  
  1175. //
  1176. // Command line token extraction class
  1177. //
  1178. class TCmdLine {
  1179.   public:
  1180.     enum Kind {Null, Name, Option, Value};
  1181.     TCmdLine(char far* cmdLine);
  1182.    ~TCmdLine();
  1183.     Kind  NextToken();
  1184.     int   TokenLen;
  1185.     char* Token;
  1186.     Kind  Type;
  1187.   private:
  1188.     char* Buf;
  1189.     Kind  NextType;
  1190. };
  1191.  
  1192. TCmdLine::TCmdLine(char far* cmdLine) : NextType(Name)
  1193. {
  1194.   Token = Buf = new char[lstrlen(cmdLine)+1];
  1195.   TokenLen = -1;         // cancels increment on next assignment
  1196.   lstrcpy(Buf, cmdLine);
  1197. }
  1198.  
  1199. TCmdLine::~TCmdLine()
  1200. {
  1201.   delete Buf;
  1202. }
  1203.  
  1204. TCmdLine::Kind TCmdLine::NextToken()
  1205. {
  1206.   Token += (TokenLen + 1);
  1207.   if (NextType == Name) {           // name or leading spaces
  1208.     Token += strspn(Token, " \t");  // skip leading white space
  1209.     switch (*Token++) {
  1210.       case 0:
  1211.         return Type = NextType = Null;
  1212.       case '=':
  1213.         Type = Value;
  1214.         break;
  1215.       case '-':
  1216.       case '/':
  1217.         Type = Option;
  1218.         break;
  1219.       default:
  1220.         Type = Name;
  1221.         Token--;
  1222.     }
  1223.   }
  1224.   else {   // must have stopped on a delimiter
  1225.     Type = NextType;
  1226.     if (Type == Null)
  1227.       return Type;
  1228.   }
  1229.   TokenLen = strcspn(Token, "=/- \t");
  1230.   char* nextToken = Token + TokenLen;
  1231.   switch (*nextToken) {
  1232.     case 0:
  1233.       NextType = Null;
  1234.       break;
  1235.     case '=':
  1236.       NextType = Value;
  1237.       break;
  1238.     case '-':
  1239.     case '/':
  1240.       NextType = Option;
  1241.       break;
  1242.     default:
  1243.       NextType = Name;
  1244.   }
  1245.   *nextToken = 0;  // null-terminate current token
  1246.   return Type;
  1247. }
  1248.  
  1249. //
  1250. // File name processing
  1251. //
  1252. enum  fileKind    { fkDispHdr, fkDispSrc, fkFullCpp,      fkCount };
  1253. char* optText[] = { "Header",  "Code",    "Definitions" };
  1254. char* fileExt[] = { "HXX",     "CXX",     "HPP" };
  1255. int   libMode[] = { tfEnum|tfAlias|tfDispatch|tfLibHeader|tfDispHeader,
  1256.                     tfDispatch|tfDispImpl, tfAllKinds|tfLibHeader };
  1257. char* stdFile[] = { ".HXX",    ".CXX",    0 };     // OC controller proxy code
  1258. char* cppFile[] = { 0,         0,         ".HPP" };// standard C++ defs
  1259.  
  1260.  
  1261. int GenerateFiles(char* libName, char** outFiles, TLogTypeInfo& log)
  1262. {
  1263.   char outName[_MAX_PATH];
  1264.   char outDrive[_MAX_DRIVE];
  1265.   char outDir  [_MAX_DIR];
  1266.   char outFName[_MAX_FNAME];
  1267.   char outExt  [_MAX_EXT];
  1268.   char libDrive[_MAX_DRIVE];
  1269.   char libDir  [_MAX_DIR];
  1270.   char libFName[_MAX_FNAME];
  1271.   char libExt  [_MAX_EXT];
  1272.   char incFile [_MAX_FNAME+_MAX_EXT+2];
  1273.   char* incName;
  1274.  
  1275.   _splitpath(libName, libDrive, libDir, libFName, libExt);
  1276.   int outCount = 0;               // count of files actually output
  1277.   for (int fileIndex = 0; fileIndex < fkCount; fileIndex++) {
  1278.     if (!outFiles[fileIndex])
  1279.       continue;
  1280.     _splitpath(outFiles[fileIndex], outDrive, outDir, outFName, outExt);
  1281.     _makepath (outName,
  1282.                outDrive[0] ? outDrive : libDrive,
  1283.                outDir[0]   ? outDir   : libDir,
  1284.                outFName[0] ? outFName : libFName,
  1285.                outExt[0]   ? outExt   : fileExt[fileIndex]);
  1286.     ofstream out;
  1287.     out.open(outName);
  1288.     ErrorIf(out.bad(), outName, IDS_OUTFILEERR);
  1289.     switch(fileIndex) {
  1290.       case fkDispHdr:
  1291.         incName = "<ocf/automacr.h>";
  1292.         incFile[0] = '"';
  1293.         _splitpath(outName, 0, 0, incFile+1, outExt);
  1294.         strcat(incFile, outExt);
  1295.         strcat(incFile, "\"");
  1296.         break;
  1297.       case fkDispSrc:
  1298.         incName = incFile;
  1299.         break;
  1300.       case fkFullCpp:
  1301.         incName = 0;
  1302.         break;
  1303.     }
  1304.     if (log.GetWindow()) {
  1305.       ::SetDlgItemText(log.GetWindow(), IDC_STATUS,  (char far*)outName);
  1306.       int* selectList = log.GetSelectList();
  1307.       int  selectCount= log.GetSelectCount();
  1308.       if (!selectList) {
  1309.         ::SendDlgItemMessage(log.GetWindow(), IDC_INFOLIST, LB_SETSEL, 1, -1);
  1310.       }
  1311.       else if (outCount != 0) {
  1312.         for (int i = 0; i < selectCount; i++)
  1313.           ::SendDlgItemMessage(log.GetWindow(), IDC_INFOLIST, LB_SETSEL, 1,
  1314.                                (LPARAM)(unsigned)selectList[i]);
  1315.       }
  1316.     }
  1317. #if 1
  1318.     ReadTypeLib(libName, incName, libMode[fileIndex], out, log);
  1319. #else
  1320. //!BB    _InitEasyWin();
  1321. //!BB    ReadTypeLib(libName, incName, libMode[fileIndex], cout, log);
  1322. #endif
  1323.     outCount++;
  1324.   }
  1325.   return 0;
  1326. }
  1327.  
  1328. #define WM_USERSTAT (WM_USER + 100)
  1329.  
  1330. bool CALLBACK __export
  1331. HelpProc(HWND hDlg, UINT msg, WPARAM /*wParam*/, LPARAM /*lParam*/)
  1332. {
  1333.   if (msg != WM_COMMAND)
  1334.     return (msg == WM_INITDIALOG);
  1335.   ::EndDialog(hDlg, TRUE);
  1336.   return true;
  1337. }
  1338.  
  1339. //
  1340. //
  1341. //
  1342. int CALLBACK __export
  1343. SelectProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM /*lParam*/)
  1344. {
  1345.   if (msg == WM_INITDIALOG) {
  1346.     int tabs = IDC_INFOLIST_TAB;
  1347.     ::SendDlgItemMessage(hDlg, IDC_INFOLIST, LB_SETTABSTOPS, 1, (LPARAM)&tabs);
  1348.     ::SendDlgItemMessage(hDlg, IDC_AUTOCODE, BM_SETCHECK, 1, 0);
  1349.     return 1;
  1350.   }
  1351.   else if (msg == WM_COMMAND) {
  1352.     switch (wParam) {
  1353.       case IDOK:
  1354.       case IDCANCEL:
  1355.         ::PostMessage(hDlg, WM_USERSTAT, wParam, 0);
  1356.         return 1;
  1357.       case IDC_SELECTALL:
  1358.       case IDC_SELECTNONE:
  1359.         ::SendDlgItemMessage(hDlg, IDC_INFOLIST, LB_SETSEL,
  1360.                              wParam==IDC_SELECTALL, -1);
  1361.         return 1;
  1362.     }
  1363.   }
  1364.   else if (msg == WM_CLOSE) {
  1365.     ::PostMessage(hDlg, WM_USERSTAT, IDABORT, 0);
  1366.   }
  1367.   return 0;
  1368. }
  1369.  
  1370. bool FillListBox(TLogTypeInfo& info)
  1371. {
  1372.   char buf[100];
  1373.   wsprintf(buf, "%s\t%s", (char far*)info.TypeKind, info.TypeName);
  1374.   ::SendDlgItemMessage(info.GetWindow(), IDC_INFOLIST, LB_ADDSTRING,
  1375.                        0, (LPARAM)(char far*)buf);
  1376.   MSG msg;
  1377.   while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  1378.     ::IsDialogMessage(info.GetWindow(), &msg);
  1379.   return true;
  1380. }
  1381.  
  1382. bool ShowProgress(TLogTypeInfo& info)
  1383. {
  1384.   HWND hWnd = info.GetWindow();
  1385.   ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_SETTOPINDEX, info.Index, 0);
  1386.   ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_SETSEL,
  1387.                        0, (LPARAM)(unsigned)info.Index);
  1388.   MSG msg;
  1389.   while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  1390.     ::IsDialogMessage(hWnd, &msg);
  1391.   return true;
  1392. }
  1393.  
  1394. bool SilentYield(TLogTypeInfo& /*info*/)
  1395. {
  1396.   MSG msg;
  1397.   while (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  1398.     ;
  1399. //  if (msg.message == WM_QUIT)
  1400. //    return false;
  1401.   return true;
  1402. }
  1403.  
  1404. const int MaxReqTypes = 20;  // maximum number of type names on command line
  1405.  
  1406. int PASCAL
  1407. WinMain(HINSTANCE hInst, HINSTANCE/*hPrev*/, char far* cmdLine, int/*show*/)
  1408. {
  1409.   TCmdLine cmd(cmdLine);
  1410.   char* outFiles[fkCount];
  1411.   int stat = 0;
  1412.  
  1413.   try {
  1414.     if (cmd.NextToken() == TCmdLine::Null) {
  1415.       //
  1416.       // If command line empty, create dialog and operate in interactive mode
  1417.       //
  1418.       char libName[_MAX_PATH];
  1419.       libName[0] = 0;
  1420.       HWND hWnd = ::CreateDialogParam(hInst, MAKEINTRESOURCE(IDD_SELECT), 0,
  1421.                                       (DLGPROC)SelectProc, 0);
  1422.  
  1423.       char title[100];
  1424.       ::LoadString(hInst, IDS_TITLE, title, sizeof(title));
  1425.       OPENFILENAME ofn = {
  1426.         sizeof(OPENFILENAME), hWnd, hInst,
  1427.         "TypeLib\0*.TLB;*.OLB\0",0,0,0,
  1428.         libName, sizeof libName, 0, 0,
  1429.         0, title,
  1430.         OFN_HIDEREADONLY | OFN_FILEMUSTEXIST,
  1431.         0,0,0,0,0,0
  1432.       };
  1433.  
  1434.       while (::GetOpenFileName(&ofn)) {
  1435.         ::SetDlgItemText(hWnd, IDC_LIBFILE, (char far*)libName);
  1436.         ::ShowWindow(hWnd, SW_SHOW);
  1437.         TLogTypeInfo fillInfo(hWnd);
  1438.         fillInfo.SetCallback(FillListBox);
  1439.         strstream temp;
  1440.         ReadTypeLib(libName, 0, tfScanOnly | tfAllKinds, temp, fillInfo);
  1441.         MSG msg;
  1442.         int stat = 0;
  1443.         while ( !stat && ::GetMessage(&msg, 0, 0, 0)) {
  1444.           if (msg.message == WM_USERSTAT)
  1445.             stat = msg.wParam;
  1446.           else
  1447.             ::IsDialogMessage(hWnd, &msg);
  1448.         }
  1449.         if (stat == IDABORT)
  1450.           break;
  1451.         if (stat == IDOK) {
  1452.           ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTALL),  SW_HIDE);
  1453.           ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTNONE), SW_HIDE);
  1454.           ::ShowWindow(::GetDlgItem(hWnd, IDC_STATUS),     SW_SHOW);
  1455.           int cppdefState = (int)::SendDlgItemMessage(hWnd, IDC_CPPDEF,
  1456.                                                      BM_GETCHECK, 0, 0);
  1457.           memcpy(outFiles, cppdefState ? cppFile : stdFile, sizeof(outFiles));
  1458.           fillInfo.SetCallback(ShowProgress);
  1459.           int* selectList = 0;
  1460.           int selectCount = (int)::SendDlgItemMessage(hWnd, IDC_INFOLIST,
  1461.                                                      LB_GETSELCOUNT, 0, 0);
  1462.           if (selectCount) {
  1463.             selectList = new int[selectCount];
  1464.             ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_GETSELITEMS,
  1465.                                  selectCount, (LPARAM)(int far*)selectList);
  1466.           }
  1467.           fillInfo.SetSelectList(selectCount, selectList);
  1468.           stat = GenerateFiles(libName, outFiles, fillInfo);
  1469.           while (!::GetFocus() ||
  1470.                   ::GetWindowTask(::GetFocus())!=::GetCurrentTask())
  1471.             if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  1472.               ::IsDialogMessage(hWnd, &msg);
  1473.           ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTALL),  SW_SHOW);
  1474.           ::ShowWindow(::GetDlgItem(hWnd, IDC_SELECTNONE), SW_SHOW);
  1475.           ::ShowWindow(::GetDlgItem(hWnd, IDC_STATUS),     SW_HIDE);
  1476.         }
  1477.         ::ShowWindow(hWnd, SW_HIDE);
  1478.         ::SendDlgItemMessage(hWnd, IDC_INFOLIST, LB_RESETCONTENT, 0, 0);
  1479.       }
  1480.       ::DestroyWindow(hWnd);
  1481.       return stat;
  1482.     }
  1483.     if (cmd.Type == TCmdLine::Name) {
  1484.       //
  1485.       //  If type library supplied on command line, operate in non-interactive
  1486.       //
  1487.       char* libName = cmd.Token;   // first argument should be a typelib name
  1488.       int optFound = 0;
  1489.       memset(outFiles, 0, sizeof(outFiles));
  1490.       char* reqTypes[MaxReqTypes];
  1491.       int   reqInfos[MaxReqTypes];
  1492.       int   reqCount = 0;
  1493.       int   optIndex = -1;
  1494.       while (cmd.NextToken() != TCmdLine::Null) {
  1495.         if (cmd.Type == TCmdLine::Option) {
  1496.           for (optIndex = 0; optIndex < fkCount; optIndex++) {
  1497.             if (strnicmp(cmd.Token, optText[optIndex], cmd.TokenLen) == 0)
  1498.               break;
  1499.           }
  1500.           ErrorIf(optIndex == fkCount, IDS_UNKNOWNOPT, cmd.Token);
  1501.           outFiles[optIndex] = "";
  1502.           optFound++;
  1503.         }
  1504.         else if (cmd.Type == TCmdLine::Value) {
  1505.           ErrorIf(optIndex == -1, IDS_MISSINGOPT, cmd.Token);
  1506.           outFiles[optIndex] = cmd.Token;
  1507.           optIndex = -1;
  1508.         }
  1509.         else {  // TCmdLine::Name  should be a class name to select
  1510.           ErrorIf(reqCount == MaxReqTypes, cmd.Token, IDS_TOOMANYTYPES);
  1511.           reqTypes[reqCount++] = cmd.Token;
  1512.         }
  1513.       }
  1514.       if (optFound == 0)  // if no file options, default to controller files
  1515.         memcpy(outFiles, stdFile, sizeof(outFiles));
  1516.       TLogTypeInfo silentInfo(0);
  1517.       if (reqCount) {
  1518.         silentInfo.SetRequestList(reqCount, reqInfos, reqTypes);
  1519.         strstream temp;
  1520.         ReadTypeLib(libName, 0, tfScanOnly | tfAllKinds, temp, silentInfo);
  1521.         char* badName = silentInfo.ExtractRequest();
  1522.         ErrorIf(badName!=0, IDS_BADTYPENAME, badName);
  1523.       }
  1524.       silentInfo.SetCallback(SilentYield);
  1525.       stat = GenerateFiles(libName, outFiles, silentInfo);
  1526.     }
  1527.     else {
  1528.       //
  1529.       //  If first command line arg is an option flag, show help dialog
  1530.       //
  1531.       stat = ::DialogBox(hInst, MAKEINTRESOURCE(IDD_HELP), 0,(DLGPROC)HelpProc);
  1532.     }
  1533.     return stat;
  1534.   }
  1535.   catch (TLocalError& xcpt) {
  1536.     char msgbuf[80];
  1537.     const char ** pmsg;
  1538.     if (*(pmsg = &xcpt.Message) <= (const char*)IDS_MAX ||
  1539.         *(pmsg = &xcpt.Title)   <= (const char*)IDS_MAX) {
  1540.       ::LoadString(hInst, *(unsigned*)pmsg, msgbuf, sizeof(msgbuf));
  1541.       *pmsg = msgbuf;
  1542.     }
  1543.     ::MessageBox(0, xcpt.Message, xcpt.Title, MB_OK);
  1544.     return 1;
  1545.   }
  1546.   catch (xmsg& xcpt) {    // should not occur, but check anyway while catching
  1547.     ::MessageBox(0, xcpt.why().c_str(), "Exception", MB_OK);
  1548.     return 2;
  1549.   }
  1550. }
  1551. 
  1552.